import json
import logging
import uuid
from sqlalchemy import exists, asc
from typing import List, Dict, Any, Optional
from sqlalchemy.orm import Session
from datetime import datetime

from src.models.session import Session as SessionModel, Message as MessageModel
from langchain_core.messages import HumanMessage, AIMessage, BaseMessage

logger = logging.getLogger(__name__)


class SessionService:
    """会话服务，处理会话和消息的CRUD操作"""

    @staticmethod
    async def create_session(db: Session, username: str) -> SessionModel:
        """创建新会话"""
        if not username:
            # 将匿名用户标记为 "unknown"
            username =  f"anonymous_{uuid.uuid4()}"
            logger.warning("创建会话时用户名缺失，使用默认值 ")
        try:
            session = SessionModel(username=username)
            db.add(session)
            db.commit()
            db.refresh(session)
            logger.info(f"Created new session with ID: {session.id} for user {username}")
            return session
        except Exception as e:
            db.rollback()
            logger.error(f"Error creating session for user {username}: {e}")
            raise

    @staticmethod
    async def get_session(db: Session, session_id: str, username: Optional[str] = None) -> Optional[SessionModel]:
        """获取会话

        Args:
            db: 数据库会话
            session_id: 要获取的会话ID
            username: 可选，用户ID，用于验证会话归属
        """
        logger.info(f"获取会话: ID={session_id}, 查询用户={username or '任意用户'}")
        try:
            query = db.query(SessionModel).filter(SessionModel.id == session_id)
            # 添加用户过滤
            if username:
                query = query.filter(SessionModel.username == username)
                logger.debug(f"添加用户过滤: {username}")

            session = query.first()

            if session:
                logger.info(f"找到会话: ID={session_id}, 用户={session.username}")
                return session

                # 会话不存在或用户不匹配
                # 检查会话是否存在（不验证用户）
                # 会话不存在或用户不匹配
            session_exists = db.query(
                exists().where(SessionModel.id == session_id)
            ).scalar()

            if exists:
                # 获取实际用户
                actual_user = db.query(SessionModel.username).filter(
                    SessionModel.id == session_id
                ).scalar()

                logger.warning(
                    f"会话存在但用户不匹配: "
                    f"请求用户={username or '未提供'}, 实际用户={actual_user or '无用户'}"
                )
            else:
                logger.warning(f"会话不存在: ID={session_id}")

            return None
        except Exception as e:
            logger.exception(f"获取会话失败: ID={session_id}, 错误={str(e)}")
            return None

    @staticmethod
    async def update_session_state(
            db: Session,
            session_id: str,
            state: Optional[Dict[str, Any]] = None,
            username: Optional[str] = None
    ) -> SessionModel:
        """更新会话状态

        Args:
            db: 数据库会话
            session_id: 要更新的会话ID
            state: 要更新的状态数据
            username: 可选，用户ID，用于验证会话归属
        """
        try:
            session = await SessionService.get_session(db, session_id, username)
            if not session:
                logger.error(f"Cannot update state: Session {session_id} not found" +
                             (f" for user {username}" if username is not None else ""))
                raise ValueError(f"Session {session_id} not found")

            if state is not None:
                session.state = state
            session.updated_at = datetime.utcnow()
            db.commit()
            db.refresh(session)
            logger.info(f"Updated state for session {session_id}")
            return session
        except Exception as e:
            db.rollback()
            logger.error(f"Error updating session state for {session_id}: {e}")
            raise

    @staticmethod
    async def add_message(
            db: Session,
            session_id: str,
            role: str,
            content: Any,
            message_type: str = "text",
            username: Optional[str] = None
    ) -> MessageModel:
        """添加消息到会话

        Args:
            db: 数据库会话
            session_id: 会话ID
            role: 消息角色（user或assistant）
            content: 消息内容
            message_type: 消息类型，默认为"text"
            username: 可选，用户ID，用于验证会话归属

        Returns:
            创建的消息对象
        """
        try:
            session = await SessionService.get_session(db, session_id, username)
            if not session:
                logger.error(f"Cannot add message: Session {session_id} not found" +
                             (f" for user {username}" if username is not None else ""))
                raise ValueError(f"Session {session_id} not found")

            # 如果content不是字符串，转为JSON字符串
            if not isinstance(content, str):
                content = json.dumps(content, ensure_ascii=False)

            message = MessageModel(
                session_id=session_id,
                role=role,
                type=message_type,
                content=content
            )
            db.add(message)
            db.commit()
            db.refresh(message)
            logger.debug(f"Added {role} message to session {session_id}")
            return message
        except Exception as e:
            db.rollback()
            logger.error(f"Error adding message to session {session_id}: {e}")
            raise

    @staticmethod
    async def get_session_messages(
            db: Session,
            session_id: str,
            username: Optional[str] = None
    ) -> List[MessageModel]:
        """获取会话的所有消息 (按时间升序)

        Args:
            db: 数据库会话
            session_id: 会话ID
            username: 可选，用户ID，用于验证会话归属
        """
        logger.info(f"获取会话消息: ID={session_id}, 请求用户={username or '任意用户'}")
        try:
            session = await SessionService.get_session(db, session_id, username)
            if not session:
                logger.warning(f"会话 {session_id} 未找到或用户 {username} 不匹配。")
                raise ValueError(f"会话 {session_id} 未找到或用户不匹配")

            query = (
                db.query(MessageModel)
                .filter(MessageModel.session_id == session_id)
                .order_by(MessageModel.created_at.asc())
            )
            
            messages = query.all()
            logger.info(f"为会话 {session_id} 检索到 {len(messages)} 条消息")
            return messages
        except ValueError as ve:
            logger.warning(str(ve))
            return [] # 会话未找到或不匹配时返回空列表
        except Exception as e:
            logger.exception(f"获取会话 {session_id} 的消息失败: {str(e)}")
            raise

    @staticmethod
    async def get_formatted_langchain_messages(
        db: Session, session_id: str, username: Optional[str] = None
    ) -> List[BaseMessage]:
        """获取会话的所有消息，并格式化为LangChain BaseMessage对象列表 (按时间升序)"""
        logger.info(
            f"获取并格式化会话消息为LangChain格式: ID={session_id}, 请求用户={username or '任意用户'}"
        )
        langchain_messages: List[BaseMessage] = []
        try:
            raw_messages = await SessionService.get_session_messages(
                db, session_id, username
            )

            for msg in raw_messages:
                if msg.role.lower() == "user":
                    langchain_messages.append(HumanMessage(content=msg.content))
                elif msg.role.lower() == "assistant" or msg.role.lower() == "ai":
                    langchain_messages.append(AIMessage(content=msg.content))
                elif msg.role.lower() == "system":
                    # 对于 'system' 类型的消息，它们通常是内部agent的输出，可以视为AI方的消息
                    # 或者根据具体情况转换为 SystemMessage，这里我们尝试将其视为AIMessage
                    # 以便让LLM感知到这些是先前AI流程的输出
                    logger.info(f"处理角色为 '{msg.role}' 的消息 ID {msg.id}，将其转换为 AIMessage。")
                    # 尝试从 message_metadata 中获取原始 agent 名称
                    agent_name = msg.role # 默认使用消息的角色名
                    if hasattr(msg, 'message_metadata') and msg.message_metadata is not None:
                        agent_name = msg.message_metadata.get("agent_name", msg.role)
                    langchain_messages.append(AIMessage(content=msg.content, name=agent_name))
                else:
                    logger.warning(f"未知消息角色 '{msg.role}' 在消息 ID {msg.id} 中，跳过。")
            
            logger.info(
                f"为会话 {session_id} 成功格式化 {len(langchain_messages)} 条 LangChain 消息"
            )
            return langchain_messages
        except Exception as e:
            logger.exception(
                f"为会话 {session_id} 获取并格式化LangChain消息失败: {str(e)}"
            )
            return [] # 出错时返回空列表，或根据策略重新抛出

    @staticmethod
    async def format_messages_for_frontend(messages: List[MessageModel]) -> List[Dict]:
        """将消息格式化为前端需要的格式"""
        try:
            formatted_messages = []
            for msg in messages:
                try:
                    # 尝试解析JSON内容
                    content = json.loads(msg.content)
                except json.JSONDecodeError:
                    # 如果不是JSON，直接使用原始内容
                    content = msg.content

                formatted_messages.append({
                    "id": msg.id,
                    "role": msg.role,
                    "type": msg.type,
                    "content": content
                })
            logger.debug(f"Formatted {len(messages)} messages for frontend")
            return formatted_messages
        except Exception as e:
            logger.error(f"Error formatting messages for frontend: {e}")
            raise
    


    @staticmethod
    async def delete_session(db: Session, session_id: str, username: Optional[str] = None) -> bool:
        """删除会话及其所有消息
        
        Args:
            db: 数据库会话
            session_id: 要删除的会话ID
            username: 可选，用户ID，用于验证会话归属
            
        Returns:
            bool: 是否成功删除
        """
        try:
            # 首先验证会话是否存在且属于该用户
            session = await SessionService.get_session(db, session_id, username)
            if not session:
                logger.warning(f"无法删除会话: ID={session_id} 不存在或不属于用户 {username}")
                return False

            # 删除所有关联的消息
            db.query(MessageModel).filter(MessageModel.session_id == session_id).delete()
            
            # 删除会话本身
            db.query(SessionModel).filter(SessionModel.id == session_id).delete()
            
            db.commit()
            logger.info(f"成功删除会话: ID={session_id} 及其所有消息")
            return True
        except Exception as e:
            db.rollback()
            logger.error(f"删除会话 {session_id} 时出错: {e}", exc_info=True)
            return False

